

#include <unistd.h>
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#include <stdarg.h>
#include <pthread.h>
#include <arpa/inet.h>

#include "log.h"
#include "list.h"
#include "rbtree.h"
#include "acl.h"
#include "aclmgr.h"


#define  RULE_CFG_DEFAULT       "policy.cfg"
#define  RULE_CFG_TEMP      	"policy.temp"

typedef struct tagRbtRule 
{
	struct rb_node stNode;
    RULE_S *pstRule;
    char szRuleName[RULE_NAME_MAXLEN+1];
} RBT_RULE_S;

unsigned int uiRuleCount = 0;
pthread_rwlock_t lockEdit;
struct list_head stRuleList = LIST_HEAD_INIT(stRuleList);
struct rb_root stRuleRbt = RB_ROOT;
bool __VALGRIND_FLAG__ = 0;

struct list_head* RULE_LIST()
{
	return &stRuleList;
}

void RBT_ObjectNodeFree(struct rb_node *pNode)
{
	RBT_OBJECT_S *pstObjectNode = rb_entry(pNode, RBT_OBJECT_S, stNode);
    free(pstObjectNode);
}

int RBT_ObjectNodeCompare(struct rb_node *pstNew, const struct rb_node *pstMember)
{
    RBT_OBJECT_S *pstNewNode = rb_entry(pstNew, RBT_OBJECT_S, stNode);
	RBT_OBJECT_S *pstMemberNode = rb_entry(pstMember, RBT_OBJECT_S, stNode);

    if (pstNewNode->uiObject > pstMemberNode->uiObject)
    {
        return RBT_GREAT;
    }
    else if (pstNewNode->uiObject < pstMemberNode->uiObject)
    {
        return RBT_LESS;
    }
    else
    {
        return RBT_EQUAL;
    }
}

RULE_S* DTQ_RuleNodeAlloc(const char *pcName)
{
    //unsigned int enObject;
    RULE_S *pstDtqRule = (RULE_S *)zalloc(sizeof(RULE_S));
    if (pstDtqRule)
    {
        strlcpy(pstDtqRule->szRuleName, pcName, sizeof(pstDtqRule->szRuleName));
        pstDtqRule->uiPriority = RULE_INVALID_PRIORITY;
        pstDtqRule->enAction = ACTION_DENY;
        pstDtqRule->stSrcIPv4Rbt = RB_ROOT;
        pstDtqRule->stDstIPv4Rbt = RB_ROOT;
        /*
        for (enObject = OBJECT_TYPE_1; enObject < OBJECT_TYPE_MAX; enObject++)
        {
            pstDtqRule->astObject[enObject] = RB_ROOT;
        }
        */
    }
    
    return pstDtqRule;
}

void DTQ_RuleNodeFree(struct list_head *pstNode)
{
    //unsigned int enObject;
    RULE_S *pstDtqRule = NULL;
    //struct rb_root *pstRbtObjRoot = NULL;

    pstDtqRule = list_entry(pstNode, RULE_S, stNode);
    rb_destory(&(pstDtqRule->stSrcIPv4Rbt), RBT_Ipv4NodeFree);
    rb_destory(&(pstDtqRule->stDstIPv4Rbt), RBT_Ipv4NodeFree);
    /*
    for (enObject = OBJECT_TYPE_1; enObject < OBJECT_TYPE_MAX; enObject++)
    {
        pstRbtObjRoot = &(pstDtqRule->astObject[enObject]);
        rb_destory(pstRbtObjRoot, RBT_ObjectNodeFree);
    }
    */
    
    free(pstDtqRule);
}

RBT_RULE_S* RBT_RuleNodeAlloc(const char *pcName, RULE_S *pstDtqRule)
{
    RBT_RULE_S *pstRbtRule = NULL;

    pstRbtRule = (RBT_RULE_S *)zalloc(sizeof(RBT_RULE_S));
    if (pstRbtRule)
    {
        strlcpy(pstRbtRule->szRuleName, pcName, sizeof(pstRbtRule->szRuleName));
        pstRbtRule->pstRule = pstDtqRule;
    }

    return pstRbtRule;
}

void RBT_RuleNodeFree(struct rb_node *pNode)
{
	RBT_RULE_S *pstRbtRule = rb_entry(pNode, RBT_RULE_S, stNode);
    free(pstRbtRule);
}

int RBT_RuleNodeCompare(struct rb_node *pstNew, const struct rb_node *pstMember)
{
    int iCmp = 0;
    RBT_RULE_S *pstNewNode = rb_entry(pstNew, RBT_RULE_S, stNode);
	RBT_RULE_S *pstMemberNode = rb_entry(pstMember, RBT_RULE_S, stNode);

    iCmp = strcmp(pstNewNode->szRuleName, pstMemberNode->szRuleName);
    if (iCmp > 0)
    {
        return RBT_GREAT;
    }
    else if (iCmp < 0)
    {
        return RBT_LESS;
    }
    else
    {
        return RBT_EQUAL;
    }
}

void* RBT_Ipv4NodeAlloc(unsigned int ipStart, unsigned int ipEnd)
{
	RBT_IPV4_S *pstIpv4Node = (RBT_IPV4_S *)zalloc(sizeof(RBT_IPV4_S));
    if (NULL != pstIpv4Node)
    {
        pstIpv4Node->stIpv4.ipStart = ipStart;
        pstIpv4Node->stIpv4.ipEnd = ipEnd;
    }
    return pstIpv4Node;
}

void RBT_Ipv4NodeFree(struct rb_node *pNode)
{
	RBT_IPV4_S *pstIpv4Node = rb_entry(pNode, RBT_IPV4_S, stNode);
    free(pstIpv4Node);
}

int RBT_Ipv4NodeCompare(struct rb_node *pstNew, const struct rb_node *pstMember)
{
    RBT_IPV4_S *pstNewNode = rb_entry(pstNew, RBT_IPV4_S, stNode);
	RBT_IPV4_S *pstMemberNode = rb_entry(pstMember, RBT_IPV4_S, stNode);

    if (pstNewNode->stIpv4.ipStart < pstMemberNode->stIpv4.ipStart)
    {
        return RBT_LESS;
    }
    else if (pstNewNode->stIpv4.ipStart > pstMemberNode->stIpv4.ipStart)
    {
        return RBT_GREAT;
    }
    else
    {
        if (pstNewNode->stIpv4.ipEnd < pstMemberNode->stIpv4.ipEnd)
        {
            return RBT_LESS;
        }
        else if (pstNewNode->stIpv4.ipEnd > pstMemberNode->stIpv4.ipEnd)
        {
            return RBT_GREAT;
        }
        else
        {
            return RBT_EQUAL;
        }
    }
}

#if 0
void RBT_PrintRule()
{
    unsigned int uiCount= 1;
	struct rb_node *pstRbtNode = NULL;
	RBT_RULE_S *pstRbtRule = NULL;
	struct rb_root *pstRbtRuleRoot = &stRuleRbt;
    
	for (pstRbtNode = rb_first(pstRbtRuleRoot); pstRbtNode; pstRbtNode = rb_next(pstRbtNode)) 
	{
		pstRbtRule = rb_entry(pstRbtNode, RBT_RULE_S, stNode);
		LOGGER("RBT_RULE %u: key=%s:", uiCount, pstRbtRule->szRuleName);
        if (pstRbtRule->pstRule)
        {
            LOGGER("RBT_RULE %u: value={%u,%s}:", uiCount, 
                    pstRbtRule->pstRule->uiPriority,
                    pstRbtRule->pstRule->szRuleName);
        }
        uiCount++;
	}

    LOGGER("#\n");
}
#endif

unsigned int add_rule(const char *pcRuleName)
{
    RBT_RULE_S stRuleFind;
    RULE_S *pstDtqRule = NULL;
    struct rb_node *pstRbtNode = NULL;
    RBT_RULE_S *pstRbtRule = NULL;

    if (uiRuleCount >= RULE_MAX_PRIORITY)
    {
        //LOGGER("rule count reach max(%u)!", RULE_MAX_PRIORITY);
        return ERROR_OVER_SPEC;
    }

    if ((NULL == pcRuleName) || (0 == pcRuleName[0]) ||
        (strlen(pcRuleName) > RULE_NAME_MAXLEN))
    {
        return ERROR_INPUT_CHK;
    }

    strlcpy(stRuleFind.szRuleName, pcRuleName, sizeof(stRuleFind.szRuleName));
	pstRbtNode = rb_find(&(stRuleFind.stNode), &stRuleRbt, RBT_RuleNodeCompare);
	if (NULL != pstRbtNode)
	{
	    //LOGGER("rule name (%s) conflict!", pcRuleName);
        return ERROR_CONFLICT;
	}

    pstDtqRule = DTQ_RuleNodeAlloc(pcRuleName);
    if (NULL == pstDtqRule)
    {
        //LOGGER("add rule name (%s) fail, no enough memory!", pcRuleName);
        return ERROR_NONE_MEMORY;
    }

    pstRbtRule = RBT_RuleNodeAlloc(pcRuleName, pstDtqRule);
    if (NULL == pstRbtRule)
    {
        DTQ_RuleNodeFree(&(pstDtqRule->stNode));
        return ERROR_NONE_MEMORY;
    }

    if (rb_add(&(pstRbtRule->stNode), &stRuleRbt, RBT_RuleNodeCompare))
    {
        RBT_RuleNodeFree(&(pstRbtRule->stNode));
        DTQ_RuleNodeFree(&(pstDtqRule->stNode));
        return ERROR_CONFLICT;
    }

    strlcpy(pstDtqRule->szRuleName, pcRuleName, sizeof(pstDtqRule->szRuleName));
    pstDtqRule->uiPriority = (uiRuleCount + 1);
    pstDtqRule->enAction = ACTION_DENY;
    list_add_tail(&(pstDtqRule->stNode), &stRuleList);
    uiRuleCount++;

    return ERROR_SUCCESS;
}

unsigned int RULE_ADD(const char *pcRuleName)
{
    unsigned int uiRet;

    EDIT_LOCK_WRITE();
    uiRet = add_rule(pcRuleName);
    EDIT_UNLOCK();
    
    return uiRet;
}

void RULE_UPDATE()
{
	unsigned int uiPriority = 1;
    RULE_S *pstNode = NULL;
    RULE_S *pstNext = NULL;

    list_for_each_entry_safe(pstNode, pstNext, &stRuleList, stNode)
    {
        pstNode->uiPriority = uiPriority;
        uiPriority++;
    }
}

void RULE_UPDATE_FROM(RULE_S *pstFromRuleNode, unsigned int uiPriority)
{
    RULE_S *pstNode = NULL;
    RULE_S *pstNext = NULL;
    unsigned int uiTempPriority = uiPriority;

	if (NULL == pstFromRuleNode)
	{
		return ;
	}

	pstNode = pstFromRuleNode;
	//LOGGER("RULE_UPDATE_FROM: %s", pstNode->szRuleName);
	list_for_each_entry_safe_from(pstNode, pstNext, &stRuleList, stNode)
    {
        pstNode->uiPriority = uiTempPriority;
        uiTempPriority++;
    }	
}

unsigned int delete_rule(const char *pcRuleName)
{
    RBT_RULE_S stRuleFind;
    struct rb_node *pstRbtNode = NULL;
    RBT_RULE_S *pstRbtRule = NULL;
	RULE_S *pstFromRuleNode = NULL;
	struct list_head *pstCurrent = NULL;
	struct list_head *pstFrom = NULL;
	unsigned int uiPriority = 1;

    if ((NULL == pcRuleName) || (0 == pcRuleName[0]))
    {
        return ERROR_INPUT_CHK;
    }

    strlcpy(stRuleFind.szRuleName, pcRuleName, sizeof(stRuleFind.szRuleName));
	pstRbtNode = rb_find(&(stRuleFind.stNode), &stRuleRbt, RBT_RuleNodeCompare);
	if (NULL == pstRbtNode)
	{
	    //LOGGER("rule name (%s) nonexist!", pcRuleName);
        return ERROR_NOT_EXIST;
	}

    pstRbtRule = rb_entry(pstRbtNode, RBT_RULE_S, stNode);
    if (NULL == pstRbtRule->pstRule)
    {
        return ERROR_FAILED;
    }
    
	pstCurrent = &(pstRbtRule->pstRule->stNode);
	if (true != list_is_last(pstCurrent, &stRuleList))
	{
		pstFrom = pstRbtRule->pstRule->stNode.next;
		uiPriority = pstRbtRule->pstRule->uiPriority;
		pstFromRuleNode = list_entry(pstFrom, RULE_S, stNode);
		RULE_UPDATE_FROM(pstFromRuleNode, uiPriority);
	}

    rb_erase(&pstRbtRule->stNode, &stRuleRbt);
    RBT_RuleNodeFree(&pstRbtRule->stNode);
	
    list_del(&(pstRbtRule->pstRule->stNode));
    DTQ_RuleNodeFree(&(pstRbtRule->pstRule->stNode));
    uiRuleCount--;

    return ERROR_SUCCESS;
}

unsigned int RULE_DEL(const char *pcRuleName)
{
    unsigned int uiRet;

    EDIT_LOCK_WRITE();
    uiRet = delete_rule(pcRuleName);
    EDIT_UNLOCK();
    
    return uiRet;
}

unsigned int delete_all_rule()
{
    RULE_S *pstNode = NULL;
    RULE_S *pstNext = NULL;

    rb_destory(&stRuleRbt, RBT_RuleNodeFree);
    list_for_each_entry_safe(pstNode, pstNext, &stRuleList, stNode)
    {
        list_del(&(pstNode->stNode));
        DTQ_RuleNodeFree(&(pstNode->stNode));
    }
    
    uiRuleCount = 0;
    return ERROR_SUCCESS;
}

unsigned int RULE_DEL_ALL()
{
    unsigned int uiRet;

    EDIT_LOCK_WRITE();
    uiRet = delete_all_rule();
    EDIT_UNLOCK();
    
    return uiRet;
}

unsigned int move_rule(const char *pcRuleName, const char *pcTarget, MOVE_DIR_E enDir)
{
    RBT_RULE_S stRuleFind;
    struct rb_node *pstRbtNode = NULL;
    struct rb_node *pstRbtDestNode = NULL;
    RBT_RULE_S *pstRbtMoveRule = NULL;
    RBT_RULE_S *pstRbtDestRule = NULL;

    if ((NULL == pcRuleName) || (0 == pcRuleName[0]))
    {
        return ERROR_INPUT_CHK;
    }

    if ((NULL != pcTarget) && (0 == strcmp(pcRuleName, pcTarget)))
    {
        //LOGGER("rule name (%s) and target cannot be same!", pcRuleName);
        return ERROR_INPUT_CHK;
    }

    strlcpy(stRuleFind.szRuleName, pcRuleName, sizeof(stRuleFind.szRuleName));
	pstRbtNode = rb_find(&(stRuleFind.stNode), &stRuleRbt, RBT_RuleNodeCompare);
	if (NULL == pstRbtNode)
	{
	    //LOGGER("rule name (%s) nonexist!", pcRuleName);
        return ERROR_NOT_EXIST;
	}

    pstRbtMoveRule = rb_entry(pstRbtNode, RBT_RULE_S, stNode);
    if (NULL == pstRbtMoveRule->pstRule)
    {
        return ERROR_FAILED;
    }
    
    if ((NULL == pcTarget) || (0 == pcTarget[0]))
    {
        list_del(&(pstRbtMoveRule->pstRule->stNode));
        if (MOVE_DIR_BEFORE == enDir)
        {
            list_add(&(pstRbtMoveRule->pstRule->stNode), &stRuleList);
        }
        else
        {
            list_add_tail(&(pstRbtMoveRule->pstRule->stNode), &stRuleList);
        }

        RULE_UPDATE();
        
        return ERROR_SUCCESS;
    }

    strlcpy(stRuleFind.szRuleName, pcTarget, sizeof(stRuleFind.szRuleName));
	pstRbtDestNode = rb_find(&(stRuleFind.stNode), &stRuleRbt, RBT_RuleNodeCompare);
	if (NULL == pstRbtDestNode)
	{
	    //LOGGER("target rule (%s) nonexist!", pcTarget);
        return ERROR_NOT_EXIST;
	}

    pstRbtDestRule = rb_entry(pstRbtDestNode, RBT_RULE_S, stNode);
    if (NULL == pstRbtDestRule->pstRule)
    {
        return ERROR_FAILED;
    }
    
    list_del(&(pstRbtDestRule->pstRule->stNode));
    if (MOVE_DIR_BEFORE == enDir)
    {
        list_add_tail(&(pstRbtDestRule->pstRule->stNode), &(pstRbtDestRule->pstRule->stNode));
    }
    else
    {
        list_add(&(pstRbtDestRule->pstRule->stNode), &(pstRbtDestRule->pstRule->stNode));
    }
    
    RULE_UPDATE();

    return ERROR_SUCCESS;
}

unsigned int RULE_MOVE(const char *pcRuleName, const char *pcTarget, MOVE_DIR_E enDir)
{
    unsigned int uiRet;

    EDIT_LOCK_WRITE();
    uiRet = move_rule(pcRuleName, pcTarget, enDir);
    EDIT_UNLOCK();
    
    return uiRet;
}

unsigned int get_rule_priority(const char *pcRuleName)
{
	unsigned int uiPriority = RULE_INVALID_PRIORITY;
    RBT_RULE_S stRuleFind;
    struct rb_node *pstRbtNode = NULL;
    RBT_RULE_S *pstRbtRule = NULL;

    if ((NULL == pcRuleName) || (0 == pcRuleName[0]))
    {
        //LOGGER("rule name (%s) invalid!", pcRuleName);
        return RULE_INVALID_PRIORITY;
    }

    strlcpy(stRuleFind.szRuleName, pcRuleName, sizeof(stRuleFind.szRuleName));
	pstRbtNode = rb_find(&(stRuleFind.stNode), &stRuleRbt, RBT_RuleNodeCompare);
	if (NULL == pstRbtNode)
	{
	    //LOGGER("rule name (%s) nonexist!", pcRuleName);
        return RULE_INVALID_PRIORITY;
	}

    pstRbtRule = rb_entry(pstRbtNode, RBT_RULE_S, stNode);
    if (NULL != pstRbtRule->pstRule)
    {
        uiPriority = pstRbtRule->pstRule->uiPriority;
    }

    return uiPriority;
}


unsigned int RULE_PRIORITY(const char *pcRuleName)
{
	unsigned int uiPriority;

    EDIT_LOCK_READ();
    uiPriority = get_rule_priority(pcRuleName);
    EDIT_UNLOCK();

    return uiPriority;
}

unsigned int RULE_COUNT()
{
    return uiRuleCount;
}

unsigned int append_src_ipv4(const char *pcRuleName, unsigned int ipStart, unsigned int ipEnd)
{
    RBT_RULE_S stRuleFind;
    struct rb_node *pstRbtNode = NULL;
    RBT_RULE_S *pstRbtRule = NULL;
    RBT_IPV4_S *pstIpv4Node = NULL;
    struct rb_root *pstRbtIPv4Root = NULL;

    if ((NULL == pcRuleName) || (0 == pcRuleName[0]))
    {
        return ERROR_INPUT_CHK;
    }

    strlcpy(stRuleFind.szRuleName, pcRuleName, sizeof(stRuleFind.szRuleName));
	pstRbtNode = rb_find(&(stRuleFind.stNode), &stRuleRbt, RBT_RuleNodeCompare);
	if (NULL == pstRbtNode)
	{
	    //LOGGER("rule name (%s) nonexist!", pcRuleName);
        return ERROR_NOT_EXIST;
	}

    pstRbtRule = rb_entry(pstRbtNode, RBT_RULE_S, stNode);
    if (NULL == pstRbtRule->pstRule)
    {
        return ERROR_FAILED;
    }

    pstIpv4Node = (RBT_IPV4_S*)RBT_Ipv4NodeAlloc(ipStart, ipEnd);
    if (NULL == pstIpv4Node)
    {
        return ERROR_NONE_MEMORY;
    }

    pstRbtIPv4Root = &(pstRbtRule->pstRule->stSrcIPv4Rbt);
    if (rb_add(&(pstIpv4Node->stNode), pstRbtIPv4Root, RBT_Ipv4NodeCompare))
    {
        free(pstIpv4Node);
        return ERROR_CONFLICT;
    }

    return ERROR_SUCCESS;
}

unsigned int RULE_APPEND_SRC_IPV4_RANGE(const char *pcRuleName, unsigned int ipStart, unsigned int ipEnd)
{
    unsigned int uiRet;

    EDIT_LOCK_WRITE();
    uiRet = append_src_ipv4(pcRuleName, ipStart, ipEnd);
    EDIT_UNLOCK();
    
    return uiRet;
}

unsigned int append_dst_ipv4(const char *pcRuleName, unsigned int ipStart, unsigned int ipEnd)
{
    RBT_RULE_S stRuleFind;
    struct rb_node *pstRbtNode = NULL;
    RBT_RULE_S *pstRbtRule = NULL;
    RBT_IPV4_S *pstIpv4Node = NULL;
    struct rb_root *pstRbtIPv4Root = NULL;

    if ((NULL == pcRuleName) || (0 == pcRuleName[0]))
    {
        return ERROR_INPUT_CHK;
    }

    strlcpy(stRuleFind.szRuleName, pcRuleName, sizeof(stRuleFind.szRuleName));
	pstRbtNode = rb_find(&(stRuleFind.stNode), &stRuleRbt, RBT_RuleNodeCompare);
	if (NULL == pstRbtNode)
	{
	    //LOGGER("rule name (%s) nonexist!", pcRuleName);
        return ERROR_NOT_EXIST;
	}

    pstRbtRule = rb_entry(pstRbtNode, RBT_RULE_S, stNode);
    if (NULL == pstRbtRule->pstRule)
    {
        return ERROR_FAILED;
    }

    pstIpv4Node = (RBT_IPV4_S*)RBT_Ipv4NodeAlloc(ipStart, ipEnd);
    if (NULL == pstIpv4Node)
    {
        return ERROR_NONE_MEMORY;
    }

    pstRbtIPv4Root = &(pstRbtRule->pstRule->stDstIPv4Rbt);
    if (rb_add(&(pstIpv4Node->stNode), pstRbtIPv4Root, RBT_Ipv4NodeCompare))
    {
        free(pstIpv4Node);
        return ERROR_CONFLICT;
    }

    return ERROR_SUCCESS;
}

unsigned int RULE_APPEND_DEST_IPV4_RANGE(const char *pcRuleName, unsigned int ipStart, unsigned int ipEnd)
{
    unsigned int uiRet;

    EDIT_LOCK_WRITE();
    uiRet = append_dst_ipv4(pcRuleName, ipStart, ipEnd);
    EDIT_UNLOCK();
    
    return uiRet;
}

unsigned int remove_src_ipv4(const char *pcRuleName, unsigned int ipStart, unsigned int ipEnd)
{
    RBT_RULE_S stRuleFind;
    struct rb_node *pstRbtNode = NULL;
    RBT_RULE_S *pstRbtRule = NULL;
    RBT_IPV4_S stIpv4Find;
    struct rb_node *pstRbtIpv4Node = NULL;
    RBT_IPV4_S *pstIpv4Node = NULL;
    struct rb_root *pstRbtIPv4Root = NULL;

    if ((NULL == pcRuleName) || (0 == pcRuleName[0]))
    {
        return ERROR_INPUT_CHK;
    }

    strlcpy(stRuleFind.szRuleName, pcRuleName, sizeof(stRuleFind.szRuleName));
	pstRbtNode = rb_find(&(stRuleFind.stNode), &stRuleRbt, RBT_RuleNodeCompare);
	if (NULL == pstRbtNode)
	{
	    //LOGGER("rule name (%s) nonexist!", pcRuleName);
        return ERROR_NOT_EXIST;
	}

    pstRbtRule = rb_entry(pstRbtNode, RBT_RULE_S, stNode);
    if (NULL == pstRbtRule->pstRule)
    {
        return ERROR_FAILED;
    }

    stIpv4Find.stIpv4.ipStart = ipStart;
    stIpv4Find.stIpv4.ipEnd = ipEnd;
    pstRbtIPv4Root = &(pstRbtRule->pstRule->stSrcIPv4Rbt);
    pstRbtIpv4Node = rb_find(&(stIpv4Find.stNode), pstRbtIPv4Root, RBT_Ipv4NodeCompare);
	if (NULL == pstRbtIpv4Node)
	{
        return ERROR_NOT_EXIST;
	}

    pstIpv4Node = rb_entry(pstRbtIpv4Node, RBT_IPV4_S, stNode);
    rb_erase(&(pstIpv4Node->stNode), pstRbtIPv4Root);
    free(pstIpv4Node);

    return ERROR_SUCCESS;
}

unsigned int RULE_REMOVE_SRC_IPV4_RANGE(const char *pcRuleName, unsigned int ipStart, unsigned int ipEnd)
{
    unsigned int uiRet;

    EDIT_LOCK_WRITE();
    uiRet = remove_src_ipv4(pcRuleName, ipStart, ipEnd);
    EDIT_UNLOCK();
    
    return uiRet;
}

unsigned int remove_dst_ipv4(const char *pcRuleName, unsigned int ipStart, unsigned int ipEnd)
{
    RBT_RULE_S stRuleFind;
    struct rb_node *pstRbtNode = NULL;
    RBT_RULE_S *pstRbtRule = NULL;
    RBT_IPV4_S stIpv4Find;
    struct rb_node *pstRbtIpv4Node = NULL;
    RBT_IPV4_S *pstIpv4Node = NULL;
    struct rb_root *pstRbtIPv4Root = NULL;

    if ((NULL == pcRuleName) || (0 == pcRuleName[0]))
    {
        return ERROR_INPUT_CHK;
    }

    strlcpy(stRuleFind.szRuleName, pcRuleName, sizeof(stRuleFind.szRuleName));
	pstRbtNode = rb_find(&(stRuleFind.stNode), &stRuleRbt, RBT_RuleNodeCompare);
	if (NULL == pstRbtNode)
	{
	    //LOGGER("rule name (%s) nonexist!", pcRuleName);
        return ERROR_NOT_EXIST;
	}

    pstRbtRule = rb_entry(pstRbtNode, RBT_RULE_S, stNode);
    if (NULL == pstRbtRule->pstRule)
    {
        return ERROR_FAILED;
    }

    stIpv4Find.stIpv4.ipStart = ipStart;
    stIpv4Find.stIpv4.ipEnd = ipEnd;
    pstRbtIPv4Root = &(pstRbtRule->pstRule->stDstIPv4Rbt);
    pstRbtIpv4Node = rb_find(&(stIpv4Find.stNode), pstRbtIPv4Root, RBT_Ipv4NodeCompare);
	if (NULL == pstRbtIpv4Node)
	{
        return ERROR_NOT_EXIST;
	}

    pstIpv4Node = rb_entry(pstRbtIpv4Node, RBT_IPV4_S, stNode);
    rb_erase(&(pstIpv4Node->stNode), pstRbtIPv4Root);
    free(pstIpv4Node);

    return ERROR_SUCCESS;
}

unsigned int RULE_REMOVE_DEST_IPV4_RANGE(const char *pcRuleName, unsigned int ipStart, unsigned int ipEnd)
{
    unsigned int uiRet;

    EDIT_LOCK_WRITE();
    uiRet = remove_dst_ipv4(pcRuleName, ipStart, ipEnd);
    EDIT_UNLOCK();
    
    return uiRet;
}

/*
unsigned int append_obj(const char *pcRuleName, OBJECT_TYPE_E enObject, unsigned int uiObj)
{
    RBT_RULE_S stRuleFind;
    struct rb_node *pstRbtNode = NULL;
    struct rb_root *pstRbtObjRoot = NULL;
    RBT_RULE_S *pstRbtRule = NULL;
    RBT_OBJECT_S *pstObjectNode = NULL;

    if ((NULL == pcRuleName) || (0 == pcRuleName[0]) || (enObject >= OBJECT_TYPE_MAX))
    {
        return ERROR_INPUT_CHK;
    }

    strlcpy(stRuleFind.szRuleName, pcRuleName, sizeof(stRuleFind.szRuleName));
	pstRbtNode = rb_find(&(stRuleFind.stNode), &stRuleRbt, RBT_RuleNodeCompare);
	if (NULL == pstRbtNode)
	{
	    //LOGGER("rule name (%s) nonexist!", pcRuleName);
        return ERROR_NOT_EXIST;
	}

    pstRbtRule = rb_entry(pstRbtNode, RBT_RULE_S, stNode);
    if (NULL == pstRbtRule->pstRule)
    {
        return ERROR_FAILED;
    }

    pstObjectNode = (RBT_OBJECT_S *)zalloc(sizeof(RBT_OBJECT_S));
    if (NULL == pstObjectNode)
    {
        return ERROR_NONE_MEMORY;
    }

    pstObjectNode->uiObject = uiObj;
    pstRbtObjRoot = &(pstRbtRule->pstRule->astObject[enObject]);
    if (rb_add(&(pstObjectNode->stNode), pstRbtObjRoot, RBT_ObjectNodeCompare))
    {
        free(pstObjectNode);
        return ERROR_CONFLICT;
    }

    return ERROR_SUCCESS;
}

unsigned int RULE_APPEND_OBJ(const char *pcRuleName, OBJECT_TYPE_E enObject, unsigned int uiObj)
{
    unsigned int uiRet;

    EDIT_LOCK_WRITE();
    uiRet = append_obj(pcRuleName, enObject, uiObj);
    EDIT_UNLOCK();
    
    return uiRet;
}

unsigned int remove_obj(const char *pcRuleName, OBJECT_TYPE_E enObject, unsigned int uiObj)
{
    RBT_RULE_S stRuleFind;
    struct rb_node *pstRbtNode = NULL;
    RBT_RULE_S *pstRbtRule = NULL;
    struct rb_node *pstRbtObjNode = NULL;
    RBT_OBJECT_S *pstObjectNode = NULL;
    struct rb_root *pstRbtObjRoot = NULL;
    RBT_OBJECT_S stObjFind;

    if ((NULL == pcRuleName) || (0 == pcRuleName[0]) || (enObject >= OBJECT_TYPE_MAX))
    {
        return ERROR_INPUT_CHK;
    }

    strlcpy(stRuleFind.szRuleName, pcRuleName, sizeof(stRuleFind.szRuleName));
	pstRbtNode = rb_find(&(stRuleFind.stNode), &stRuleRbt, RBT_RuleNodeCompare);
	if (NULL == pstRbtNode)
	{
	    //LOGGER("rule name (%s) nonexist!", pcRuleName);
        return ERROR_NOT_EXIST;
	}

    pstRbtRule = rb_entry(pstRbtNode, RBT_RULE_S, stNode);
    if (NULL == pstRbtRule->pstRule)
    {
        return ERROR_FAILED;
    }

    stObjFind.uiObject = uiObj;
    pstRbtObjRoot = &(pstRbtRule->pstRule->astObject[enObject]);
    pstRbtObjNode = rb_find(&(stObjFind.stNode), pstRbtObjRoot, RBT_ObjectNodeCompare);
	if (NULL == pstRbtObjNode)
	{
	    //LOGGER("object (%u) nonexist!", uiObj);
        return ERROR_NOT_EXIST;
	}

    pstObjectNode = rb_entry(pstRbtObjNode, RBT_OBJECT_S, stNode);
    rb_erase(&(pstObjectNode->stNode), pstRbtObjRoot);
    free(pstObjectNode);

    return ERROR_SUCCESS;
}

unsigned int RULE_REMOVE_OBJ(const char *pcRuleName, OBJECT_TYPE_E enObject, unsigned int uiObj)
{
    unsigned int uiRet;

    EDIT_LOCK_WRITE();
    uiRet = remove_obj(pcRuleName, enObject, uiObj);
    EDIT_UNLOCK();
    
    return uiRet;
}

RULE_SUMMARY_S get_first_rule_by_obj(OBJECT_TYPE_E enObject, unsigned int uiObj)
{
    RULE_S *pstNode = NULL;
    RULE_S *pstNext = NULL;
    struct rb_node *pstRbtNode = NULL;
	RBT_OBJECT_S *pstObjectNode = NULL;
    struct rb_root *pstRbtObjRoot = NULL;
    RULE_SUMMARY_S stNotMatch = MATCH_NONE;
    RULE_SUMMARY_S stRuleMatch = MATCH_NONE;

    if (enObject >= OBJECT_TYPE_MAX)
    {
    	return stNotMatch;
    }
    
    list_for_each_entry_safe(pstNode, pstNext, &stRuleList, stNode)
    {
        pstRbtObjRoot = &(pstNode->astObject[enObject]);
        if (true == rb_is_emplty(pstRbtObjRoot))
        {
            stRuleMatch.uiPriority = pstNode->uiPriority;
            strlcpy(stRuleMatch.szRuleName, pstNode->szRuleName, sizeof(stRuleMatch.szRuleName));
            return stRuleMatch;
        }

	    for (pstRbtNode = rb_first(pstRbtObjRoot); pstRbtNode; pstRbtNode = rb_next(pstRbtNode)) 
		{
			pstObjectNode = rb_entry(pstRbtNode, RBT_OBJECT_S, stNode);
            if (pstObjectNode->uiObject == uiObj)
            {
                stRuleMatch.uiPriority = pstNode->uiPriority;
                strlcpy(stRuleMatch.szRuleName, pstNode->szRuleName, sizeof(stRuleMatch.szRuleName));
                return stRuleMatch;
            }
	    }
    }

    return stNotMatch;
} 

RULE_SUMMARY_S MATCH_FIRST_RULE_BY_OBJ(OBJECT_TYPE_E enObject, unsigned int uiObj)
{
    RULE_SUMMARY_S stRuleMatch;

    EDIT_LOCK_READ();
    stRuleMatch = get_first_rule_by_obj(enObject, uiObj);
    EDIT_UNLOCK();

    return stRuleMatch;
}
*/

RULE_SUMMARY_S get_first_rule_by_src_ipv4(unsigned int uiIPv4)
{
    RULE_S *pstNode = NULL;
    RULE_S *pstNext = NULL;
    struct rb_root *pstRbtIpv4Root = NULL;
    struct rb_node *pstRbtNode = NULL;
    RBT_IPV4_S *pstIpv4Node = NULL;
    RULE_SUMMARY_S stNotMatch = MATCH_NONE;
    RULE_SUMMARY_S stRuleMatch = MATCH_NONE;
    
    list_for_each_entry_safe(pstNode, pstNext, &stRuleList, stNode)
    {
        pstRbtIpv4Root = &(pstNode->stSrcIPv4Rbt);
        if (true == rb_is_emplty(pstRbtIpv4Root))
        {
            stRuleMatch.uiPriority = pstNode->uiPriority;
            strlcpy(stRuleMatch.szRuleName, pstNode->szRuleName, sizeof(stRuleMatch.szRuleName));
            return stRuleMatch;
        }

        for (pstRbtNode = rb_first(pstRbtIpv4Root); pstRbtNode; pstRbtNode = rb_next(pstRbtNode)) 
		{
			pstIpv4Node = rb_entry(pstRbtNode, RBT_IPV4_S, stNode);
            if ((uiIPv4 >= pstIpv4Node->stIpv4.ipStart) && (uiIPv4 <= pstIpv4Node->stIpv4.ipEnd))
            {
                stRuleMatch.uiPriority = pstNode->uiPriority;
                strlcpy(stRuleMatch.szRuleName, pstNode->szRuleName, sizeof(stRuleMatch.szRuleName));
                return stRuleMatch;
            }
	    }
    }

    return stNotMatch;
}

RULE_SUMMARY_S MATCH_FIRST_RULE_BY_SRC_IPV4(unsigned int uiIPv4)
{
    RULE_SUMMARY_S stRuleMatch;

    EDIT_LOCK_READ();
    stRuleMatch = get_first_rule_by_src_ipv4(uiIPv4);
    EDIT_UNLOCK();

    return stRuleMatch;
}

RULE_SUMMARY_S get_first_rule_by_dst_ipv4(unsigned int uiIPv4)
{
    RULE_S *pstNode = NULL;
    RULE_S *pstNext = NULL;
    struct rb_root *pstRbtIpv4Root = NULL;
    struct rb_node *pstRbtNode = NULL;
    RBT_IPV4_S *pstIpv4Node = NULL;
    RULE_SUMMARY_S stNotMatch = MATCH_NONE;
    RULE_SUMMARY_S stRuleMatch = MATCH_NONE;
    
    list_for_each_entry_safe(pstNode, pstNext, &stRuleList, stNode)
    {
        pstRbtIpv4Root = &(pstNode->stDstIPv4Rbt);
        if (true == rb_is_emplty(pstRbtIpv4Root))
        {
            stRuleMatch.uiPriority = pstNode->uiPriority;
            strlcpy(stRuleMatch.szRuleName, pstNode->szRuleName, sizeof(stRuleMatch.szRuleName));
            return stRuleMatch;
        }

        for (pstRbtNode = rb_first(pstRbtIpv4Root); pstRbtNode; pstRbtNode = rb_next(pstRbtNode)) 
		{
			pstIpv4Node = rb_entry(pstRbtNode, RBT_IPV4_S, stNode);
            if ((uiIPv4 >= pstIpv4Node->stIpv4.ipStart) && (uiIPv4 <= pstIpv4Node->stIpv4.ipEnd))
            {
                stRuleMatch.uiPriority = pstNode->uiPriority;
                strlcpy(stRuleMatch.szRuleName, pstNode->szRuleName, sizeof(stRuleMatch.szRuleName));
                return stRuleMatch;
            }
	    }
    }

    return stNotMatch;
}

RULE_SUMMARY_S MATCH_FIRST_RULE_BY_DEST_IPV4(unsigned int uiIPv4)
{
    RULE_SUMMARY_S stRuleMatch;

    EDIT_LOCK_READ();
    stRuleMatch = get_first_rule_by_dst_ipv4(uiIPv4);
    EDIT_UNLOCK();

    return stRuleMatch;
}

unsigned int save_cfg(const char *pcCfgName)
{
    FILE *pstFile = NULL;
    RULE_S *pstNode = NULL;
    RULE_S *pstNext = NULL;
    struct rb_node *pstRbtNode = NULL;
	//RBT_OBJECT_S *pstObjectNode = NULL;
    RBT_IPV4_S *pstIpv4Node = NULL;
    //struct rb_root *pstRbtObjRoot = NULL;
    struct rb_root *pstRbtIpv4Root = NULL;
    //unsigned int enObject;
    char szIpStart[IPV4_MAX_LEN+1] = { 0 };
    char szIpEnd[IPV4_MAX_LEN+1] = { 0 };

    if ((NULL == pcCfgName) || (0 == pcCfgName[0]))
    {
        return ERROR_INPUT_CHK;
    }

    pstFile = fopen(RULE_CFG_TEMP, "a+");
    if (NULL == pstFile)
    {
        return ERROR_FAILED;
    }

    fprintf (pstFile, "\n");
    fprintf (pstFile, "rule count: %u\n", uiRuleCount);
    list_for_each_entry_safe(pstNode, pstNext, &stRuleList, stNode)
    {
        fprintf (pstFile, "rule name %s\n", pstNode->szRuleName);
        fprintf (pstFile, "  priority %u\n", pstNode->uiPriority);
        /*
        for (enObject = OBJECT_TYPE_1; enObject < OBJECT_TYPE_MAX; enObject++)
        {
            pstRbtObjRoot = &(pstNode->astObject[enObject]);
    	    for (pstRbtNode = rb_first(pstRbtObjRoot); pstRbtNode; pstRbtNode = rb_next(pstRbtNode)) 
    		{
    			pstObjectNode = rb_entry(pstRbtNode, RBT_OBJECT_S, stNode);
                fprintf (pstFile, "  object-type-%u %u\n", enObject, pstObjectNode->uiObject);
    	    }
        }
        */

        pstRbtIpv4Root = &(pstNode->stSrcIPv4Rbt);
        for (pstRbtNode = rb_first(pstRbtIpv4Root); pstRbtNode; pstRbtNode = rb_next(pstRbtNode)) 
		{
			pstIpv4Node = rb_entry(pstRbtNode, RBT_IPV4_S, stNode);
            ipv4_to_string(ntohl(pstIpv4Node->stIpv4.ipStart), szIpStart, sizeof(szIpStart));
            ipv4_to_string(ntohl(pstIpv4Node->stIpv4.ipEnd), szIpEnd, sizeof(szIpEnd));
            fprintf (pstFile, "  src-ipv4 from %s to %s\n", szIpStart, szIpEnd);
	    }
	    pstRbtIpv4Root = &(pstNode->stDstIPv4Rbt);
        for (pstRbtNode = rb_first(pstRbtIpv4Root); pstRbtNode; pstRbtNode = rb_next(pstRbtNode)) 
		{
			pstIpv4Node = rb_entry(pstRbtNode, RBT_IPV4_S, stNode);
            ipv4_to_string(ntohl(pstIpv4Node->stIpv4.ipStart), szIpStart, sizeof(szIpStart));
            ipv4_to_string(ntohl(pstIpv4Node->stIpv4.ipEnd), szIpEnd, sizeof(szIpEnd));
            fprintf (pstFile, "  dst-ipv4 from %s to %s\n", szIpStart, szIpEnd);
	    }
    }
    fprintf (pstFile, "\n");

    fclose(pstFile);

    rename(RULE_CFG_TEMP, pcCfgName);

    return ERROR_SUCCESS;
}

unsigned int RULE_SAVE_CFG(const char *pcCfgName)
{
    unsigned int uiRet;

    EDIT_LOCK_READ();
    uiRet = save_cfg(pcCfgName);
    EDIT_UNLOCK();

    return uiRet;
}

unsigned int RULE_SAVE_DEFAULT()
{
    return RULE_SAVE_CFG(RULE_CFG_DEFAULT);
}

unsigned int print_cfg()
{
    RULE_S *pstNode = NULL;
    RULE_S *pstNext = NULL;
    struct rb_node *pstRbtNode = NULL;
	//RBT_OBJECT_S *pstObjectNode = NULL;
    RBT_IPV4_S *pstIpv4Node = NULL;
    //struct rb_root *pstRbtObjRoot = NULL;
    struct rb_root *pstRbtIpv4Root = NULL;
    char szIpStart[IPV4_MAX_LEN+1] = { 0 };
    char szIpEnd[IPV4_MAX_LEN+1] = { 0 };
    //unsigned int enObject;

    printf ("\n");
    printf ("rule count: %u\n", uiRuleCount);
    list_for_each_entry_safe(pstNode, pstNext, &stRuleList, stNode)
    {
        printf ("rule name %s\n", pstNode->szRuleName);
        printf ("  priority %u\n", pstNode->uiPriority);
        /*
        for (enObject = OBJECT_TYPE_1; enObject < OBJECT_TYPE_MAX; enObject++)
        {
            pstRbtObjRoot = &(pstNode->astObject[enObject]);
    	    for (pstRbtNode = rb_first(pstRbtObjRoot); pstRbtNode; pstRbtNode = rb_next(pstRbtNode)) 
    		{
    			pstObjectNode = rb_entry(pstRbtNode, RBT_OBJECT_S, stNode);
                printf ("  object-type-%u %u\n", enObject, pstObjectNode->uiObject);
    	    }
        }
        */

        pstRbtIpv4Root = &(pstNode->stSrcIPv4Rbt);
        for (pstRbtNode = rb_first(pstRbtIpv4Root); pstRbtNode; pstRbtNode = rb_next(pstRbtNode)) 
		{
			pstIpv4Node = rb_entry(pstRbtNode, RBT_IPV4_S, stNode);
            ipv4_to_string(ntohl(pstIpv4Node->stIpv4.ipStart), szIpStart, sizeof(szIpStart));
            ipv4_to_string(ntohl(pstIpv4Node->stIpv4.ipEnd), szIpEnd, sizeof(szIpEnd));
            printf ("  src-ipv4 from %s to %s\n", szIpStart, szIpEnd);
	    }
	    pstRbtIpv4Root = &(pstNode->stDstIPv4Rbt);
        for (pstRbtNode = rb_first(pstRbtIpv4Root); pstRbtNode; pstRbtNode = rb_next(pstRbtNode)) 
		{
			pstIpv4Node = rb_entry(pstRbtNode, RBT_IPV4_S, stNode);
            ipv4_to_string(ntohl(pstIpv4Node->stIpv4.ipStart), szIpStart, sizeof(szIpStart));
            ipv4_to_string(ntohl(pstIpv4Node->stIpv4.ipEnd), szIpEnd, sizeof(szIpEnd));
            printf ("  dst-ipv4 from %s to %s\n", szIpStart, szIpEnd);
	    }
    }
    printf ("\n");

    return ERROR_SUCCESS;
}

void RULE_PRINT_CFG()
{
    EDIT_LOCK_READ();
    print_cfg();
    EDIT_UNLOCK();
}

void __attribute__((constructor(PRIORITY_ACLMGR))) ACL_MGR_INIT()
{
    EDIT_LOCK_INIT();
}

void __attribute__((destructor(PRIORITY_ACLMGR))) ACL_MGR_EXIT()
{
    RULE_DEL_ALL();
    EDIT_LOCK_DESTROY();
}

